#include "public_def.h"

#include "sock.h"
#include "rtp.h"
#include "rtspser.h"
#include "rtcpser.h"
#include "utils.h"

#define PUT_16(p,v) ((p)[0]=((v)>>8)&0xff,(p)[1]=(v)&0xff)
#define PUT_32(p,v) ((p)[0]=((v)>>24)&0xff,(p)[1]=((v)>>16)&0xff,(p)[2]=((v)>>8)&0xff,(p)[3]=(v)&0xff)

//        0                   1                   2                   3
//        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//header |V=2|P|    RC   |   PT=RR=201   |             length            |
//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//       |                     SSRC of packet sender                     |
//       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//report |                 SSRC_1 (SSRC of first source)                 |
//block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//  1    | fraction lost |       cumulative number of packets lost       |
//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//       |           extended highest sequence number received           |
//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//       |                      interarrival jitter                      |
//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//       |                         last SR (LSR)                         |
//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//       |                   delay since last SR (DLSR)                  |
//       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//report |                 SSRC_2 (SSRC of second source)                |
//block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//  2    :                               ...                             :
//       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//       |                  profile-specific extensions                  |
//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
void RTCP_Print_RR(uint8 * pBuf, uint16 iLen)
{
	uint8 *p = pBuf;
	uint16 * length;
	uint32 * SSRC, * SSRC_1, *lastSR;
	p += 2;
	length = (uint16 *)p;
	*length = ntohs(*length);
	dbgprintf(0, "RTCP RR message:\n");
	dbgprintf(0, "RTCP RR message.Length: %d\n", *length);
	if (*length < 2) 
	{
		return;
	}
	p += 2;
	SSRC = (uint32*)p;
	*SSRC = ntohl(*SSRC);
	dbgprintf(0, "RTCP RR message.SSRC: %u\n", *SSRC);
	p += 4;
	SSRC_1 = (uint32*)p;
	*SSRC_1 = ntohl(*SSRC_1);
	dbgprintf(0, "RTCP RR message.SSRC_1: %u\n", *SSRC_1);
	p = pBuf + 24;
	lastSR = (uint32*)p;
	*lastSR = ntohl(*lastSR);
	dbgprintf(0, "RTCP RR message.lastSR: %u\n", *lastSR);
}

//    0                   1                   2                   3
//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//   |V=2|P| subtype |   PT=APP=204  |             length            |
//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//   |                           SSRC/CSRC                           |
//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//   |                          name (ASCII)                         |
//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//   |                   application-dependent data                ...
//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
void RTCP_Print_APP(uint8 * pBuf, uint16 iLen)
{
	uint8 *p = pBuf;
	uint16 * length;
	uint32 * SSRC, *data;
	char * name;
	p += 2;
	length = (uint16 *)p;
	*length = ntohs(*length);
	dbgprintf(0, "RTCP APP message:\n");
	dbgprintf(0, "RTCP APP message.Length: %u\n", *length);
	p += 2;
	SSRC = (uint32*)p;
	*SSRC = ntohl(*SSRC);
	dbgprintf(0, "RTCP APP message.SSRC: %08X\n", ntohl(*SSRC));
	p += 4;
	name = (char *)p;
	dbgprintf(0, "RTCP APP message.name: %c%c%c%c\n", name[0], name[1], name[2], name[3]);
	p += 4;
	data = (uint32 *)p;
	dbgprintf(0, "RTCP APP message.data: %08X\n", ntohl(*data));
	if (*length == 5)
	{
		p += 4;
		data = (uint32 *)p;
		dbgprintf(0, "RTCP APP message.data: %08X", ntohl(*data));
		p += 4;
		data = (uint32 *)p;
		dbgprintf(0, "%08X\n", ntohl(*data));
	}
	else
	{
		p += 4;
		data = (uint32 *)p;
		dbgprintf(0, "RTCP APP message.data: %08X\n", ntohl(*data));
	}
	
}

int RTCP_Send_ACK(RTSPConnection_t *pConn, uint8 * pBuf, int iLen, bool blVideo) //blVideo = true: video, else audio
{
	//dbgprintf(0, "Send ACK to %s", pConn->remoteip);
	return send(((blVideo) ? (pConn->vrtcpSock.sock) : (pConn->artcpSock.sock)), pBuf, iLen, 0);
}


//        0                   1                   2                   3
//        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//header |V=2|P|    RC   |   PT=RR=201   |             length            |
//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//       |                     SSRC of packet sender                     |
//       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//report |                 SSRC_1 (SSRC of first source)                 |
//block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//  1    | fraction lost |       cumulative number of packets lost       |
//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//       |           extended highest sequence number received           |
//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//       |                      interarrival jitter                      |
//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//       |                         last SR (LSR)                         |
//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//       |                   delay since last SR (DLSR)                  |
//       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//report |                 SSRC_2 (SSRC of second source)                |
//block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//  2    :                               ...                             :
//       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//       |                  profile-specific extensions                  |
//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

int RTCP_Send_SR(RTSPConnection_t *pConn, RTPSession_t * rtp, bool blVideo) //blVideo = true: video, else audio
{
	struct timeval now;
	uint8 pBuf[MAX_UDP_PACKET_LEN];
	unsigned int ntp_sec, ntp_usec;

#ifdef _WIN32
	time_t clock;
	struct tm tm;
	SYSTEMTIME wtm;

	GetLocalTime(&wtm);
	tm.tm_year = wtm.wYear - 1900;
	tm.tm_mon = wtm.wMonth - 1;
	tm.tm_mday = wtm.wDay;
	tm.tm_hour = wtm.wHour;
	tm.tm_min = wtm.wMinute;
	tm.tm_sec = wtm.wSecond;
	tm.tm_isdst = -1;
	clock = mktime(&tm);
	now.tv_sec = clock;
	now.tv_usec = wtm.wMilliseconds * 1000;
#else
	gettimeofday(&now, NULL);
#endif

	ntp_sec = now.tv_sec + 0x83AA7E80;
	ntp_usec = (double)( (double)now.tv_usec * (double)0x4000000 ) / 15625.0;
	
	pBuf[0] = 2 << 6; // version
	pBuf[1] = 200;		// packet type is Sender Report
	PUT_16( pBuf + 2, 6 ); // length in words minus one
	PUT_32( pBuf + 4, ((blVideo) ? (rtp->vhdr.ssrc) : (rtp->ahdr.ssrc)));
	PUT_32( pBuf + 8, ntp_sec);
	PUT_32( pBuf + 12, ntp_usec );
	PUT_32( pBuf + 16, ((blVideo) ? (rtp->vhdr.ts) : (rtp->ahdr.ts)));
	PUT_32( pBuf + 20, ((blVideo) ? (rtp->vpkt_count) : (rtp->apkt_count)));
	PUT_32( pBuf + 24, ((blVideo) ? (rtp->voctet_count) : (rtp->aoctet_count)));
	pBuf[28] = ( 2 << 6 ) | 1; // version; source count = 1
	pBuf[29] = 202; // packet type is Source Description
	PUT_16( pBuf + 30, 4 ); // length in words minus one
	PUT_32( pBuf + 32, ((blVideo) ? (rtp->vhdr.ssrc) : (rtp->ahdr.ssrc)));
	pBuf[36] = 0x01; // field type is CNAME
	pBuf[37] = 13; // text length
	memcpy( pBuf + 38, "DIGIBIRD stream", 13);
    
	if (pConn)
	{

		if (blVideo)
		{
			if (pConn->vrtcpSock.m_iOpen)
			{
				send(pConn->vrtcpSock.sock, pBuf, 51, 0 );
			}
		}
		else
		{
			if (pConn->artcpSock.m_iOpen)
			{
				send(pConn->artcpSock.sock, pBuf, 51, 0 );
			}
		}
	}

	return 0;
}

int RTCP_Send_SR_New(RTSPConnection_t *pConn, RTPSession_t * rtp, bool blVideo) //blVideo = true: video, else audio
{
	struct timeval now;
	uint8 pBuf[MAX_UDP_PACKET_LEN];
	unsigned int ntp_sec, ntp_usec;

#ifdef _WIN32
	time_t clock;
	struct tm tm;
	SYSTEMTIME wtm;

	GetLocalTime(&wtm);
	tm.tm_year = wtm.wYear - 1900;
	tm.tm_mon = wtm.wMonth - 1;
	tm.tm_mday = wtm.wDay;
	tm.tm_hour = wtm.wHour;
	tm.tm_min = wtm.wMinute;
	tm.tm_sec = wtm.wSecond;
	tm.tm_isdst = -1;
	clock = mktime(&tm);
	now.tv_sec = clock;
	now.tv_usec = wtm.wMilliseconds * 1000;
#else
	gettimeofday(&now, NULL);
#endif

	ntp_sec = now.tv_sec + 0x83AA7E80;
	ntp_usec = (double)( (double)now.tv_usec * (double)0x4000000 ) / 15625.0;
	
	pBuf[0] = 2 << 6; // version
	pBuf[1] = 200;		// packet type is Sender Report
	PUT_16( pBuf + 2, 6 ); // length in words minus one
	PUT_32( pBuf + 4, ((blVideo) ? (rtp->vhdr.ssrc) : (rtp->ahdr.ssrc)));
	PUT_32( pBuf + 8, ntp_sec);
	PUT_32( pBuf + 12, ntp_usec );
	PUT_32( pBuf + 16, ((blVideo) ? (rtp->vhdr.ts) : (rtp->ahdr.ts)));
	PUT_32( pBuf + 20, ((blVideo) ? (rtp->vpkt_count) : (rtp->apkt_count)));
	PUT_32( pBuf + 24, ((blVideo) ? (rtp->voctet_count) : (rtp->aoctet_count)));
	pBuf[28] = ( 2 << 6 ) | 1; // version; source count = 1
	pBuf[29] = 202; // packet type is Source Description
	PUT_16( pBuf + 30, 4 ); // length in words minus one
	PUT_32( pBuf + 32, ((blVideo) ? (rtp->vhdr.ssrc) : (rtp->ahdr.ssrc)));
	pBuf[36] = 0x01; // field type is CNAME
	pBuf[37] = 13; // text length
	memcpy( pBuf + 38, "DIGIBIRD stream", 13);
	if (pConn)
	{
		if (blVideo)
		{
			SendClientData((char *)pBuf, 51, pConn, 1);
		}
		else
		{
			SendClientData((char *)pBuf, 51, pConn, 3);
		}
				
	}

	return 0;
}

void RTCPGetRTSPConnection(RTSPServer_t *svr, struct sockaddr_in	*addr, int port,  RTSPConnection_t ** retConn,  bool * blVideo)
{
	RTSPConnection_t * pConn;
	*retConn = NULL;
	int i, j;
	char ip[16];
	unsigned short ush_ClientPort = myntols(addr->sin_port);
	strcpy(ip, inet_ntoa(addr->sin_addr));
	HI_CHInfo_t * info = svr->m_tChnInfo;
	
	for(i = 0; i < svr->chCount; i++)
	{
		if (((info->RTPAPort + 1) == port) || ((info->RTPVPort + 1) == port) || ((info->RTPAPort) == port)||((info->RTPVPort) == port) )
		{
			*blVideo = ((info->RTPVPort + 1) == port);
			
			for(j = 0; j < AC_Count(svr->listRTSPConnection); j++)
			{
				pConn = AC_Get(svr->listRTSPConnection, j);
				if (pConn && i == pConn->chID)
				{
					//dbgprintf(0, "The client port is %d", pConn->rtpVPort + 1);
					if (strcmp(pConn->remoteip, ip) == 0)
					{
						if(((pConn->rtpAPort + 1) == ush_ClientPort) || ((pConn->rtpVPort + 1) == ush_ClientPort)|| ((info->RTPAPort) == port)||((info->RTPVPort) == port))
						{
							//dbgprintf(0, "find the client");
							*retConn = pConn;
							return;
						}
						
					}
				}
			}
		}

		info++;
	}
}

int RTCPOnSocketRecvCallBack(void * pBuf, int iLen, struct sockaddr_in	*pAddr, int iPort, void *pParam)
{
	uint8 flag = ((uint8 *)pBuf)[1];
	bool blVideo = true;
	RTSPConnection_t * pConn;
	dbgprintf(0, "flag = %d", flag);
	switch(flag)
	{
		case 200 : //SR
			break;
		case 201 : //RR
			
			RTCP_Print_RR(pBuf, iLen);
			Global_lock();
			RTCPGetRTSPConnection(g_ptRTSPServer, pAddr, iPort, &pConn, &blVideo);
			if (pConn)
			{
				RTSPMarkLastAccess(pConn);
				//dbgprintf(0, "RTSPMarkLastAccess flag = %s", inet_ntoa(pConn->rtspSock->addr->sin_addr));
				#if 0
				if (pConn->active)
				{
					HI_CHInfo_t * ch = g_ptRTSPServer->m_tChnInfo;
					ch += pConn->chID;
					RTCP_Send_SR(pConn, &ch->rtpSession, blVideo);
				}
				#endif 
			}
			Global_unlock();
			break;
		case 202 : //SDES
			break;
		case 203 : //BYE
			break;
		case 204:
			break;
			//RTCP_Print_APP(pBuf, iLen);
			Global_lock();
			RTCPGetRTSPConnection(g_ptRTSPServer, pAddr, iPort, &pConn, &blVideo);
			if (pConn)
			{
				RTCP_Send_ACK(pConn, pBuf, iLen, blVideo);
			}
			Global_unlock();
			break;
	}
	return 0;
}

int RTCPOnSocketRecvCallBackWithIndex(void * pBuf, int iLen, struct sockaddr_in	*pAddr, int index, void *pParam)
{
	
	int iChn = index/4;
	int iIsVideo = index%4;
	dbgprintf(0, "iIsVideo = %d ",iIsVideo);
	#if 0
	if(iIsVideo  > 1)
	{
		return 0;
	}
	#endif
	int port = 0;
	HI_CHInfo_t * ch = g_ptRTSPServer->m_tChnInfo;
	ch += iChn;
	switch(iIsVideo)
	{
		case 0:
			port = ch->RTPAPort + 1;
			break;
		case 1:
			port = ch->RTPVPort + 1;
			break;
		case 2:
			port = ch->RTPAPort;
			break;
		case 3:
			port = ch->RTPVPort;
			break;
		default:
			break;
			
	}
	#if 0
	if(iIsVideo)
	{
		port = ch->RTPVPort + 1;
	}
	else
	{
		port = ch->RTPAPort + 1;
	}	
	#endif
	RTCPOnSocketRecvCallBack(pBuf, iLen, pAddr,port, pParam);
	return 0;
}

